// Copyright lowRISC contributors (OpenTitan project).
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

#ifndef OPENTITAN_SW_DEVICE_LIB_DIF_DIF_FLASH_CTRL_H_
#define OPENTITAN_SW_DEVICE_LIB_DIF_DIF_FLASH_CTRL_H_

/**
 * @file
 * @brief <a href="/hw/top_earlgrey/ip_autogen/flash_ctrl/doc/">Flash
 * Controller</a> Device Interface Functions
 */

#include "sw/device/lib/base/macros.h"
#include "sw/device/lib/base/multibits.h"

#include "sw/device/lib/dif/autogen/dif_flash_ctrl_autogen.h"

#ifdef __cplusplus
extern "C" {
#endif  // __cplusplus

/**
 * Carries state for a flash controller device.
 *
 * All members except the `dev` should be considered private and should not be
 * accessed directly outside of the DIF implementation.
 */
typedef struct dif_flash_ctrl_state {
  /**
   * Contains autogenerated device information, like the base address for
   * registers in the flash controller device.
   */
  dif_flash_ctrl_t dev;

  /* Private members below. */

  /** Number of words remaining for the current transaction. */
  uint32_t words_remaining;
  /** Whether a transaction is pending completion. */
  bool transaction_pending;
} dif_flash_ctrl_state_t;

/**
 * Initialize the DIF state for the flash controller.
 *
 * @param handle The flash controller DIF state to initialize.
 * @param base_addr The base address for the flash controller.
 * @return `kDifBadArg` if `handle` is null. `kDifOk` otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_init_state(dif_flash_ctrl_state_t *handle,
                                       mmio_region_t base_addr);

/**
 * Initialize the DIF state for the flash controller.
 *
 * @param handle The flash controller DIF state to initialize.
 * @param dt The flash controller dt.
 * @return `kDifBadArg` if `handle` is null. `kDifOk` otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_init_state_from_dt(dif_flash_ctrl_state_t *handle,
                                               dt_flash_ctrl_t dt);

typedef struct dif_flash_ctrl_device_info {
  /** Number of banks under this flash controller. */
  uint32_t num_banks;
  /** Number of bytes per flash word. */
  uint32_t bytes_per_word;
  /** Number of bytes per flash page. */
  uint32_t bytes_per_page;
  /** Number of pages per bank in the data partition. */
  uint32_t data_pages;
  /** Number of pages per bank in the info partition, type 0. */
  uint32_t info0_pages;
  /** Number of pages per bank in the info partition, type 1. */
  uint32_t info1_pages;
  /** Number of pages per bank in the info partition, type 2. */
  uint32_t info2_pages;
} dif_flash_ctrl_device_info_t;

// TODO: Associate the data with a base address or acknowledge that there
// should only ever be one flash controller in the system.
/**
 * Get information on the flash controller sizes.
 *
 * @return A `dif_flash_ctrl_device_info_t` representing the feature sizes for
 * various components of the flash.
 */
OT_WARN_UNUSED_RESULT
dif_flash_ctrl_device_info_t dif_flash_ctrl_get_device_info(void);

/**
 * Set whether the flash is enabled.
 *
 * Generally, this is used to disable flash functionality in case of an
 * emergency. Flash functionality is ordinarily enabled.
 *
 * @param handle The flash controller to operate on.
 * @param enable Enable/disable flash functionality.
 * @return `kDifBadArg` if `handle` is null. `kDifOk` otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_set_flash_enablement(dif_flash_ctrl_state_t *handle,
                                                 dif_toggle_t enable);

/**
 * Get whether flash functionality is enabled.
 *
 * @param handle The flash controller to operate on.
 * @param enabled_out Out parameter, where to store whether flash is enabled.
 * @return `kDifBadArg` if `handle` or `enabled_out` are null and `kDifOk`
 * otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_get_flash_enablement(
    const dif_flash_ctrl_state_t *handle, dif_toggle_t *enabled_out);

/**
 * Set whether execution / fetch access is enabled.
 *
 * @param handle The flash controller to operate on.
 * @param enable Enable/disable execution / fetch access.
 * @return `kDifBadArg` if `handle` or `enabled_out` are null and `kDifOk`
 * otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_set_exec_enablement(dif_flash_ctrl_state_t *handle,
                                                dif_toggle_t enable);

/**
 * Get whether execution / fetch access is enabled.
 *
 * @param handle The flash controller to operate on.
 * @param enabled_out Out parameter, whether execution / fetch access is
 * allowed.
 * @return `kDifBadArg` if `handle` or `enabled_out` are null and `kDifOk`
 * otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_get_exec_enablement(
    const dif_flash_ctrl_state_t *handle, dif_toggle_t *enabled_out);

/**
 * Begins the flash controller's initialization sequence. The flash controller
 * will read out the root seeds before allowing other usage of the controller.
 * This operation will only be performed once, and controller initialization
 * cannot be requested again until after a reset.
 *
 * @param handle The flash controller to operate on.
 * @return `kDifBadArg` if `handle` is null, `kDifError` if initialization has
 * already been started, and `kDifOk` otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_start_controller_init(
    dif_flash_ctrl_state_t *handle);

/**
 * Status bits that can be queried.
 */
typedef struct dif_flash_ctrl_status {
  /**
   * Flash read FIFO full, software must consume data.
   */
  bool read_fifo_full : 1;
  /**
   * Flash read FIFO empty.
   */
  bool read_fifo_empty : 1;
  /**
   * Flash program FIFO full.
   */
  bool prog_fifo_full : 1;
  /**
   * Flash program FIFO empty, software must provide data.
   */
  bool prog_fifo_empty : 1;
  /**
   * Flash controller undergoing init.
   */
  bool controller_init_wip : 1;
  /**
   * Flash controller initialized.
   */
  bool controller_initialized : 1;
} dif_flash_ctrl_status_t;

/**
 * Query the status registers on the flash controller.
 *
 * This function checks the various status bits as described in
 * `dif_flash_ctrl_status_t`.
 *
 * @param handle flash controller device to check the status bits for.
 * @param status_out Out parameter. The current status of the flash controller.
 * @return `kDifBadArg` if `handle` or `status_out` is null, `kDifOk` otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_get_status(const dif_flash_ctrl_state_t *handle,
                                       dif_flash_ctrl_status_t *status_out);

/**
 * Represents programming capabilities of the flash controller. The meaning of
 * the boolean values is context-sensitive. For the result of a query, they
 * represent which types are allowed. As an argument to a function that disables
 * capabilities, a true value indicates that the function should disable that
 * type.
 */
typedef struct dif_flash_ctrl_prog_capabilities {
  /** Normal programming type. */
  bool normal_prog_type : 1;
  /** Repair programming type. */
  bool repair_prog_type : 1;
} dif_flash_ctrl_prog_capabilities_t;

/**
 * Query the allowed programming types.
 *
 * Note that this function is a check of a permission only. For checking whether
 * the flash supports a given type, use `dif_flash_ctrl_get_phy_status()`.
 * @sa dif_flash_ctrl_get_phy_status
 *
 * @param handle The flash controller to query.
 * @param allowed_types_out Out parameter. Points to location where the allowed
 * types should be written.
 * @return `kDifBadArg` if `handle` or `allowed_types_out` are null. `kDifOk`
 * otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_get_allowed_prog_types(
    const dif_flash_ctrl_state_t *handle,
    dif_flash_ctrl_prog_capabilities_t *allowed_types_out);

/**
 * Disallow the indicated programming operations.
 *
 * Note that this is a one-way operation. Programming types that are disabled
 * cannot be enabled again without a reset.
 *
 * @param handle The flash controller to operate on.
 * @param types_to_disallow A programming type marked true indicates that the
 * given type should be *disabled*.
 * @return `kDifBadArg` if handle is null. `kDifOk` otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_disallow_prog_types(
    dif_flash_ctrl_state_t *handle,
    dif_flash_ctrl_prog_capabilities_t types_to_disable);

/**
 * Enum to represent the flash partition type (data or info).
 */
typedef enum dif_flash_ctrl_partition_type {
  kDifFlashCtrlPartitionTypeData = 0,
  kDifFlashCtrlPartitionTypeInfo = 1
} dif_flash_ctrl_partition_type_t;

typedef enum dif_flash_ctrl_operation {
  /** Read the specified number of words. */
  kDifFlashCtrlOpRead = 0,
  /** Program the specified number of words (normal mode). */
  kDifFlashCtrlOpProgram = 1,
  /**
   * Program the specified number of words in repair mode. Support for this
   * mode depends on the underlying flash technology. See
   * `dif_flash_ctrl_supports_repair_operation`.
   */
  kDifFlashCtrlOpProgramRepair = 5,
  /** Erase the specified page. */
  kDifFlashCtrlOpPageErase = 2,
  /** Erase the specified bank. */
  kDifFlashCtrlOpBankErase = 10,
} dif_flash_ctrl_operation_t;

typedef struct dif_flash_ctrl_transaction {
  dif_flash_ctrl_operation_t op;
  /**
   * The partition type for the transaction.
   *
   * Note: For bank erase operations, the data partition is *always* erased,
   * even when `partition_type` is `kFlashCtrlPartitionTypeInfo`.
   *
   */
  dif_flash_ctrl_partition_type_t partition_type;
  /**
   * The index / ID of the info partition. Unused for data partitions, since
   * there is only one in a given bank.
   */
  uint32_t partition_id;
  /**
   * Byte address (in the flash address space) to start the operation.
   *
   * For operations at a granularity of words, the flash controller will
   * truncate to the closest, lower word aligned address. For example, if 0x13
   * is supplied for a read, the controller will perform a read at address 0x10.
   *
   * Similarly, for page erase and bank erase operations, the flash controller
   * will truncate to the closest lower page-aligned or bank-aligned address,
   * respectively.
   */
  uint32_t byte_address;
  /**
   * Number of 32-bit words in the operation. Must be in the range [1,4096]
   * (inclusive) for program or read operations. Unused for erase operations.
   */
  uint32_t word_count;
} dif_flash_ctrl_transaction_t;

/**
 * Start a flash controller operation.
 *
 * Note that not all underlying flash memory supports the
 * `kDifFlashCtrlOpProgramRepair` operation. When specifying this in the `op`,
 * `dif_flash_ctrl_get_phy_status()` can first be used to ensure the operation
 * is supported.
 *
 * @param handle The flash controller device to execute the transaction on.
 * @param transaction The parameters that constitute the operation to start.
 * @return `kDifBadArg` if `handle` is null or `transaction` contains an invalid
 * or unsupported operation, `kDifUnavailable` if a flash transaction is in
 * progress at the controller, `kDifIpFifoFull` if the FIFOs are not empty, and
 * `kDifOk` otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_start(dif_flash_ctrl_state_t *handle,
                                  dif_flash_ctrl_transaction_t transaction);

/**
 * Start a flash controller operation, with fewer safeguards. (unsafe version)
 *
 * Unlike `dif_flash_ctrl_start()`, this variant does not check whether the info
 * partition id is valid, whether the word count is valid, or whether the FIFOs
 * have been emptied. This function is intended to be used to trigger errors on
 * purpose, for testing the hardware responses.
 *
 * Note that not all underlying flash memory supports the
 * `kDifFlashCtrlOpProgramRepair` operation. When specifying this in the `op`,
 * `dif_flash_ctrl_get_phy_status()` can first be used to ensure the operation
 * is supported.
 *
 * @param handle The flash controller device to execute the transaction on.
 * @param transaction The parameters that constitute the operation to start.
 * @return `kDifBadArg` if `handle` is null, `kDifUnavailable` if a flash
 * transaction is in progress, and `kDifOk` otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_start_unsafe(
    dif_flash_ctrl_state_t *handle, dif_flash_ctrl_transaction_t transaction);

/**
 * Suspend an ongoing erase transaction.
 *
 * If no erase transaction is ongoing, returns with no effect.
 *
 * @param handle flash controller device to operate on.
 * @return `kDifBadArg` if `handle` is null. Otherwise, `kDifOk`.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_suspend_erase(dif_flash_ctrl_state_t *handle);

/**
 * Query the controller for any erase suspension requests pending.
 *
 * @param handle The flash controller to query.
 * @param request_pending_out Out parameter. The location to write whether an
 * erase suspension request is pending.
 * @return `kDifBadArg` if `handle` or `request_pending_out` are null. `kDifOk`
 * otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_get_erase_suspend_status(
    dif_flash_ctrl_state_t *handle, bool *request_pending_out);

/**
 * Push data to the program FIFO. (unsafe version)
 *
 * This function is primarily for testing hardware error responses. If you are
 * not specifically trying to force an error, consider
 * `dif_flash_ctrl_prog_fifo_push()` instead. This function does not check if a
 * program transaction has begun, nor if the number of words would exceed the
 * size of the current transaction.
 *
 * Attempts to write the contents of `data` to the program FIFO without
 * consideration for the current controller state.
 *
 * It is up to the caller to call `dif_flash_ctrl_end()` to ensure the
 * flash controller completed this transaction successfully.
 *
 * @param handle flash controller device to push data to.
 * @param word_count The number of words to write.
 * @param data The data to write.
 * @return `kDifBadArg` if `handle` or `data` are null. `kDifOk` otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_prog_fifo_push_unsafe(
    dif_flash_ctrl_state_t *handle, uint32_t word_count, const uint32_t *data);

/**
 * Push data to the program FIFO.
 *
 * Attempts to write the contents of `data` to the program FIFO. It is required
 * that a program transaction be started prior to calling this function, else
 * the call will fail with `kDifError`.
 *
 * The following conditions are also required:
 *   - `data` must reference a contiguous, allocated, readable region of at
 *     least `word_count` words, violation of this will produce undefined
 *     behavior.
 *   - The first call to this function after starting the program transaction
 *     the same `word_count` must not exceed what was supplied at the start of
 *     the program transaction.
 *   - Each subsequent call the new `word_count` must not exceed `word_count -
 *     words_sent_out` from the previous call.
 * All deviations on the above will produce a `kDifBadArg` error
 * unless otherwise specified.
 *
 * If the FIFO fills up, this function will cause the CPU to block until the
 * flash controller frees up more space.
 *
 * It is up to the caller to call `dif_flash_ctrl_end()` to ensure the
 * flash controller completed this transaction successfully.
 *
 * @param handle flash controller device to push data to.
 * @param word_count The number of words to write.
 * @param data The data to write.
 * program FIFO, will contain the number of words pushed.
 * @return `kDifBadArg` if `handle` or `data` are null or if the value of
 * `word_count` is illegal. `kDifError` if a program transaction was not
 * started. `kDifOk` otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_prog_fifo_push(dif_flash_ctrl_state_t *handle,
                                           uint32_t word_count,
                                           const uint32_t *data);

/**
 * Read data from the read FIFO. (unsafe version)
 *
 * This function is primarily for testing hardware error responses. If you are
 * not specifically trying to force an error, consider
 * `dif_flash_ctrl_read_fifo_pop()` instead. This function does not check if a
 * transaction is currently in progress, nor if this would cause a read beyond
 * the number of words for the current operation.
 *
 * Attempts to read `word_count` words from the read FIFO without consideration
 * for the current controller state.
 *
 * It is up to the caller to call `dif_flash_ctrl_end()` to ensure the
 * flash controller completed this transaction successfully.
 *
 * @param handle flash controller device to push data to.
 * @param word_count The number of words to read.
 * @param data_out The region in memory to store the data read off the FIFO.
 * @return `kDifBadArg` if `handle` or `data` are null. `kDifOk` otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_read_fifo_pop_unsafe(dif_flash_ctrl_state_t *handle,
                                                 uint32_t word_count,
                                                 uint32_t *data_out);

/**
 * Read data from the read FIFO.
 *
 * Attempts to read `word_count` words from the read FIFO.
 *
 * The following conditions are required:
 *   - `data_out` must reference a contiguous, allocated, writable region of at
 *     least `word_count` words, violation of this will produce undefined
 *     behavior.
 *   - The first call to this function after starting the program transaction
 *     the same `word_count` must not exceed what was supplied at the start of
 * the read transaction.
 *   - Each subsequent call the new `word_count` must not exceed `word_count -
 *     words_received` from the previous call.
 * All deviations on the above will produce a `kDifBadArg` error unless
 * otherwise specified.
 *
 * If the FIFO empties this function will cause the CPU to block until the flash
 * controller fills the FIFO with more data.
 *
 * It is up to the caller to call `dif_flash_ctrl_end()` to ensure the
 * flash controller completed this transaction successfully.
 *
 * @param handle flash controller device to pull data from.
 * @param word_count The number of words to read.
 * @param data_out The region in memory to store the data read off the FIFO.
 * @param words_read_out Out-parameter, the number of words read.
 * @return `kDifBadArg` if `handle` or `data_out` are null, or if the value of
 * `word_count` is illegal. `kDifOk` otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_read_fifo_pop(dif_flash_ctrl_state_t *handle,
                                          uint32_t word_count,
                                          uint32_t *data_out);

typedef struct dif_flash_ctrl_error_codes {
  /**
   * Access permission error.
   */
  bool memory_properties_error : 1;
  /**
   * Uncorrectable flash read data error.
   */
  bool read_error : 1;
  /**
   * Flash program has a window resolution error. In other words, the start of
   * program and end of program are in different windows.
   */
  bool prog_window_error : 1;
  /**
   * Flash program operation selected an unavailable type. For example, the
   * repair type of programming was selected, but the flash did not support it.
   */
  bool prog_type_error : 1;
  /**
   * A shadow register encountered an update error.
   */
  bool shadow_register_error : 1;
} dif_flash_ctrl_error_codes_t;

/**
 * Represents recoverable errors and synchronous errors caused by software.
 */
typedef struct dif_flash_ctrl_error {
  /**
   * For errors associated with an address, the address where the error
   * occurred.
   */
  uint32_t address;

  /**
   * A set of error codes.
   */
  dif_flash_ctrl_error_codes_t codes;
} dif_flash_ctrl_error_t;

/**
 * Get the error codes and address of the last associated error.
 *
 * @param handle flash controller device to query.
 * @param error_code_out Output parameter. The location where the current status
 * is to be stored.
 * @return `kDifBadArg` if `handle` or `error_code_out` are null. `kDifOk`
 * otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_get_error_codes(
    const dif_flash_ctrl_state_t *handle,
    dif_flash_ctrl_error_t *error_code_out);

/**
 * Clear the error codes.
 *
 * @param handle flash controller device to set.
 * @return `kDifBadArg` if `handle` is null. `kDifOk` otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_clear_error_codes(
    dif_flash_ctrl_state_t *handle, dif_flash_ctrl_error_codes_t codes);

typedef struct dif_flash_ctrl_output {
  /**
   * The error code associated with an `operation_error`. This field is only
   * valid if `operation_error` is true.
   */
  dif_flash_ctrl_error_t error_code;
  /**
   * Flash operation done.
   */
  bool operation_done : 1;
  /**
   * Flash operation error.
   */
  bool operation_error : 1;

} dif_flash_ctrl_output_t;

/**
 * Check that the transaction has completed and return any resulting error
 * codes. Does not clear the error codes, but does clear the operation status if
 * the operation has terminated.
 *
 * @param handle flash controller device for completing the transaction.
 * @param out Out parameter. Contains the transaction status and error codes.
 * @return `kDifBadArg` if `handle` or `out` are null, `kDifError` if no
 * transaction was pending, `kDifUnavailable` if the controller is still
 * processing the transaction, `kDifIpFifoFull` if there are still words
 * remaining for the FIFOs, and `kDifOk` otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_end(dif_flash_ctrl_state_t *handle,
                                dif_flash_ctrl_output_t *out);

/**
 * Memory protection configuration options.
 */
typedef struct dif_flash_ctrl_region_properties {
  /** Read enable flag. */
  multi_bit_bool_t rd_en;
  /** Program enable flag. */
  multi_bit_bool_t prog_en;
  /** Erase enable flag. */
  multi_bit_bool_t erase_en;
  /** Scramble enable flag*/
  multi_bit_bool_t scramble_en;
  /** ECC enable flag. */
  multi_bit_bool_t ecc_en;
  /** High-endurance enable flag. */
  multi_bit_bool_t high_endurance_en;
} dif_flash_ctrl_region_properties_t;

/**
 * A composite of a data region and its memory properties.
 */
typedef struct dif_flash_ctrl_data_region_properties {
  /** Region base page index. */
  uint32_t base;
  /** Region config size (in number of pages). */
  uint32_t size;
  /** Memory properties of the region. */
  dif_flash_ctrl_region_properties_t properties;
} dif_flash_ctrl_data_region_properties_t;

/**
 * Representation of the memory protection regions for the info pages.
 */
typedef struct dif_flash_ctrl_info_region {
  /** Region bank ID. */
  uint32_t bank;
  /** Region info partition ID. */
  uint32_t partition_id;
  /** Region page index. */
  uint32_t page;
} dif_flash_ctrl_info_region_t;

/**
 * Enable/disable the data region of flash indexed by `region`.
 *
 * This may only be done if region configuration has not been locked.
 *
 * @param handle flash controller device to configure.
 * @param region The region to operate on.
 * @param enable Enable or disable this `region`.
 * @return `kDifBadArg` if `handle` is null or `region` is invalid, `kDifLocked`
 * if region configuration has been locked, and `kDifOk` otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_set_data_region_enablement(
    dif_flash_ctrl_state_t *handle, uint32_t region, dif_toggle_t enable);

/**
 * Get the enabled/disabled state for the indicated data `region`.
 *
 * @param handle flash controller device to query.
 * @param region The region in question.
 * @param enabled_out Out-parameter, the enabled/disabled state of this region.
 * @return `kDifBadArg ` if `handle` or `enabled_out` is null, or if `region` is
 * invalid, `kDifOk` otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_get_data_region_enablement(
    const dif_flash_ctrl_state_t *handle, uint32_t region,
    dif_toggle_t *enabled_out);

/**
 * Enable/disable the info region of flash identified by `region`.
 *
 * This may only be done if region configuration has not been locked.
 *
 * @param handle flash controller device to configure.
 * @param region The region to operate on.
 * @param enable Enable or disable this `region`.
 * @return `kDifBadArg` if `handle` is null or `region` is invalid, `kDifLocked`
 * if region configuration has been locked, and `kDifOk` otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_set_info_region_enablement(
    dif_flash_ctrl_state_t *handle, dif_flash_ctrl_info_region_t region,
    dif_toggle_t enable);

/**
 * Get the enabled/disabled state for the indicated info `region`.
 *
 * @param handle flash controller device to query.
 * @param region The region in question.
 * @param enabled_out Out-parameter, the enabled/disabled state of this region.
 * @return `kDifBadArg ` if `handle` or `enabled_out` is null, or if `region` is
 * invalid, `kDifOk` otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_get_info_region_enablement(
    const dif_flash_ctrl_state_t *handle, dif_flash_ctrl_info_region_t region,
    dif_toggle_t *enabled_out);

/**
 * Set the default memory properties for data regions, when not overridden by a
 * specific entry in the data region memory properties table.
 *
 * @param handle flash controller device to configure.
 * @param properties The memory properties to control.
 * @return `kDifBadArg` if `handle` is null, `kDifOk` otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_set_default_region_properties(
    dif_flash_ctrl_state_t *handle,
    dif_flash_ctrl_region_properties_t properties);

/**
 * Get the default memory properties for data regions, when they are not
 * overridden by a specific entry in the data region memory properties table.
 *
 * @param handle flash controller device to query.
 * @param properties_out Out-parameter, a pointer to a
 * `dif_flash_ctrl_region_properties_t` struct for writing the memory
 * properties.
 * @return `kDifBadArg` if `handle` or `properties_out` are null. `kDifOk`
 * otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_get_default_region_properties(
    const dif_flash_ctrl_state_t *handle,
    dif_flash_ctrl_region_properties_t *properties_out);

/**
 * Set memory properties for the data region of flash indexed by `region`.
 *
 * This may only be done if region configuration has not been locked.
 *
 * @param handle flash controller device to configure.
 * @param region The region to operate on.
 * @param config The memory properties to control for this `region`.
 * @return `kDifBadArg` if `handle` is null or `region` is invalid, `kDifLocked`
 * if region configuration has been locked, and `kDifOk` otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_set_data_region_properties(
    dif_flash_ctrl_state_t *handle, uint32_t region,
    dif_flash_ctrl_data_region_properties_t config);

/**
 * Get the memory properties for the data region of flash indexed by `region`.
 *
 * @param handle flash controller device to query.
 * @param region The index of the region entry in question.
 * @param config_out Out-parameter, a pointer to a
 * `dif_flash_ctrl_data_region_properties_t` struct for writing the full entry
 * showing the region configuration and its memory properties.
 * @return `kDifBadArg` if `handle` or `properties_out` are null or if `region`
 * is invalid. `kDifOk` otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_get_data_region_properties(
    const dif_flash_ctrl_state_t *handle, uint32_t region,
    dif_flash_ctrl_data_region_properties_t *config_out);

/**
 * Set memory properties for the info region of flash identified by `region`.
 *
 * This may only be done if region configuration has not been locked.
 *
 * @param handle flash controller device to configure.
 * @param region The region to operate on.
 * @param properties The memory properties to control for this `region`.
 * @return `kDifBadArg` if `handle` is null or `region` is invalid, `kDifLocked`
 * if region configuration has been locked, and `kDifOk` otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_set_info_region_properties(
    dif_flash_ctrl_state_t *handle, dif_flash_ctrl_info_region_t region,
    dif_flash_ctrl_region_properties_t properties);

/**
 * Get the memory properties for the info region of flash identified by
 * `region`.
 *
 * @param handle flash controller device to query.
 * @param region The index of the region entry in question.
 * @param properties_out Out-parameter, a pointer to a
 * `dif_flash_ctrl_region_properties_t` struct for writing memory properties
 * associated with the indicated `region`.
 * @return `kDifBadArg` if `handle` or `properties_out` are null or if `region`
 * is invalid. `kDifOk` otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_get_info_region_properties(
    const dif_flash_ctrl_state_t *handle, dif_flash_ctrl_info_region_t region,
    dif_flash_ctrl_region_properties_t *properties_out);

/**
 * Lock data region memory properties configuration until the device is reset.
 *
 * This will prevent any further configuration of region properties until device
 * reset. Future calls to functions that set data region memory properties will
 * return `kDifLocked`.
 *
 * @param handle flash controller device to lock region configuration on.
 * @param region The region to lock.
 * @return `kDifBadArg` if `handle` is null, or if `region` is invalid,
 * `kDifLocked` if configuration is already locked, `kDifOk` otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_lock_data_region_properties(
    dif_flash_ctrl_state_t *handle, uint32_t region);

/**
 * Lock info region memory properties configuration until the device is reset.
 *
 * This will prevent any further configuration of region properties until device
 * reset. Future calls to functions that set info region memory properties will
 * return `kDifLocked`.
 *
 * @param handle flash controller device to lock region configuration on.
 * @param region The region to lock.
 * @return `kDifBadArg` if `handle` is null, or if `region` is invalid,
 * `kDifLocked` if configuration is already locked, `kDifOk` otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_lock_info_region_properties(
    dif_flash_ctrl_state_t *handle, dif_flash_ctrl_info_region_t region);

/**
 * Query the state of the region configuration lock for the given data `region`
 * entry's index.
 *
 * This function checks if memory region configuration is still enabled or if it
 * has been locked. Once locked, region configuration cannot be enabled again,
 * and all calls to region configuration functions will return `kDifLocked`
 * until the device is restarted.
 *
 * @param handle flash controller device to check the lock state for.
 * @param region The region in question.
 * @param locked_out Out-parameter, the current state of the region's
 * configuration lock.
 * @return `kDifBadArg` if `handle` or `locked_out` is null, or if `region` is
 * invalid, `kDifOk` otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_data_region_is_locked(
    const dif_flash_ctrl_state_t *handle, uint32_t region, bool *locked_out);

/**
 * Query the state of the region configuration lock for the given info `region`.
 *
 * This function checks if memory region configuration is still enabled or if it
 * has been locked. Once locked, region configuration cannot be enabled again,
 * and all calls to region configuration functions will return `kDifLocked`
 * until the device is restarted.
 *
 * @param handle flash controller device to check the lock state for.
 * @param region The region in question.
 * @param locked_out Out-parameter, the current state of the region's
 * configuration lock.
 * @return `kDifBadArg` if `handle` or `locked_out` is null, or if `region` is
 * invalid, `kDifOk` otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_info_region_is_locked(
    const dif_flash_ctrl_state_t *handle, dif_flash_ctrl_info_region_t region,
    bool *locked_out);

/**
 * Enable/disable erase operations for a particular flash bank.
 *
 * This may only be done if bank configuration is still enabled.
 *
 * @param handle flash controller device to operate on.
 * @param bank The bank to configure.
 * @param enable Enable/disable erase access for this bank.
 * @return `kDifBadArg` if `handle` is null or `bank` is invalid, `kDifLocked`
 * if bank configuration is locked, and `kDifOk` otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_set_bank_erase_enablement(
    dif_flash_ctrl_state_t *handle, uint32_t bank, dif_toggle_t enable);

/**
 * Query the erase permissions for a particular flash bank.
 *
 * @param handle flash controller device to query.
 * @param bank The bank to query.
 * @param enabled_out Out-parameter, the erase permissions for this bank.
 * @return `kDifBadArg` if `handle` or `enabled_out` is null and `kDifOk`
 * otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_get_bank_erase_enablement(
    const dif_flash_ctrl_state_t *handle, uint32_t bank,
    dif_toggle_t *enabled_out);

/**
 * Lock bank configuration until the device is reset.
 *
 * This will prevent any further configuration of memory banks until device
 * reset. Future calls to bank configuration functions will return `kDifLocked`.
 *
 * @param handle flash controller device to lock region configuration on.
 * @return `kDifBadArg` if `handle` is null, `kDifLocked` if already locked,
 * and `kDifOk` otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_lock_bank_configuration(
    dif_flash_ctrl_state_t *handle);

/**
 * Query the state of the bank configuration lock.
 *
 * This function checks if memory bank configuration is still enabled or if it
 * has been locked. Once locked, bank configuration cannot be enabled again, and
 * all calls to bank configuration functions will return `kDifLocked` until the
 * device is restarted.
 *
 * @param handle flash controller device to check the lock state for.
 * @param locked_out Out-parameter, the current state of the bank configuration
 * lock.
 * @return `kDifBadArg` if `handle` or `locked_out` is null, `kDifOk` otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_bank_configuration_is_locked(
    const dif_flash_ctrl_state_t *handle, bool *locked_out);

/**
 * Set the interrupt watermarks for the program FIFO.
 *
 * The value of `level` defines the level the program FIFO must drain to before
 * triggering a `prog_lvl` interrupt.
 *
 * This interrupts will only trigger if enabled through the interrupt API.
 *
 * @param handle flash controller to set FIFO level watermarks for.
 * @param prog Trigger an interrupt when the program FIFO drains to this level.
 * @return `kDifBadArg` if `handle` is null or if the value `level` is out of
 * range, `kDifOk` otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_set_prog_fifo_watermark(
    dif_flash_ctrl_state_t *handle, uint32_t level);

/**
 * Set the interrupt watermarks for the read FIFO.
 *
 * The value of `level` defines the level the read FIFO must fill to before
 * triggering a `rd_lvl` interrupt.
 *
 * This interrupt will only trigger if enabled through the interrupt API.
 *
 * @param handle flash controller to set FIFO level watermarks for.
 * @param level Trigger an interrupt when the read FIFO fills to this level.
 * @return `kDifBadArg` if `flash_ctrl` is null or if the value of `prog` is out
 * of range, `kDifOk` otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_set_read_fifo_watermark(
    dif_flash_ctrl_state_t *handle, uint32_t level);

/**
 * Get the interrupt watermarks for the program and read FIFOs.
 *
 * @param handle flash controller to get FIFO level watermarks from.
 * @param prog_out Out-parameter, the prog FIFO watermark level. If the prog
 * FIFO empties to this level, a corresponding status bit and possibly an
 * interrupt may be generated. May be null.
 * @param read_out Out-parameter, the read FIFO watermark level. If the read
 * FIFO fills to this level, a corresponding status bit and possibly an
 * interrupt may be generated. May be null.
 * @return `kDifBadArg` if `handle` is null, `kDifOk` otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_get_fifo_watermarks(
    const dif_flash_ctrl_state_t *handle, uint32_t *prog_out,
    uint32_t *read_out);

/**
 * Resets both the program and read FIFOs.
 *
 * This is useful in the event of an unexpected error as a means of reseting
 * state.
 *
 * @param handle flash controller device to clear FIFOs on.
 * @return `kDifBadArg` if `handle` is null, `kDifOk` otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_reset_fifos(dif_flash_ctrl_state_t *handle);

typedef struct dif_flash_ctrl_faults {
  /** The flash hardware interface encountered a memory permission error. */
  bool memory_properties_error : 1;
  /** The flash hardware interface encountered a read data error. */
  bool read_error : 1;
  /** The flash hardware interface encountered a program resolution error. */
  bool prog_window_error : 1;
  /** The flash hardware interface encountered a program type error. */
  bool prog_type_error : 1;
  /** A host transaction was granted with illegal properties. */
  bool host_gnt_error : 1;
  /** The flash controller encountered a register integrity error. */
  bool register_integrity_error : 1;
  /** The flash memory encountered a register integrity error. */
  bool phy_integrity_error : 1;
  /** The lifecycle management interface encountered a fatal error. */
  bool lifecycle_manager_error : 1;
  /** A shadow register encountered a storage fault. */
  bool shadow_storage_error : 1;
} dif_flash_ctrl_faults_t;

/**
 * Gets the unrecoverable or hardware faults.
 *
 * @param handle flash controller device to query
 * @param faults_out Out parameter, a pointer to the location to write the fault
 * values.
 * @return `kDifBadArg` if `handle` or `fault_out` are null. `kDifOk` otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_get_faults(const dif_flash_ctrl_state_t *handle,
                                       dif_flash_ctrl_faults_t *faults_out);

typedef struct dif_flash_ctrl_ecc_errors {
  /** Count of the number of single-bit ECC errors. */
  uint32_t single_bit_error_count;
  /** The last address that produced a single-bit ECC error. */
  uint32_t last_error_address;
} dif_flash_ctrl_ecc_errors_t;

/**
 * Get the ECC error information for the specified flash `bank`.
 *
 * @param handle The flash controller device to query.
 * @param bank The desired bank to look up errors for.
 * @return `kDifBadArg` if `handle` or `errors_out` are null or if `bank` is
 * invalid. `kDifOk` otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_get_ecc_errors(
    const dif_flash_ctrl_state_t *handle, uint32_t bank,
    dif_flash_ctrl_ecc_errors_t *errors_out);

typedef struct dif_flash_ctrl_phy_status {
  /** Flash phy controller is initializing. */
  bool phy_init_wip : 1;
  /** Normal programming is supported. */
  bool prog_normal_available : 1;
  /** Repair programming is supported. */
  bool prog_repair_available : 1;
} dif_flash_ctrl_phy_status_t;

/**
 * Query the status registers on the flash controller.
 *
 * This function checks the various status bits as described in
 * `dif_flash_ctrl_phy_status_t`.
 *
 * @param handle The flash controller device with the desired phy's status bit
 * to check.
 * @param status_out Out-parameter, the current status of the flash phy.
 * @return `kDifBadArg` if `handle` or `status_out` is null, `kDifOk`
 * otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_get_phy_status(
    const dif_flash_ctrl_state_t *handle,
    dif_flash_ctrl_phy_status_t *status_out);

/**
 * Set the value of the scratch register.
 *
 * @param handle The flash controller device to operate on.
 * @param value The value to set the scratch register to.
 * @return `kDifBadArg` if `handle` is null, `kDifOk` otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_set_scratch(dif_flash_ctrl_state_t *handle,
                                        uint32_t value);

/**
 * Get the value of the scratch register.
 *
 * @param handle The flash controller device to query.
 * @param value_out Out parameter. The location to write the scratch register's
 * value to.
 * @return `kDifBadArg` if `handle` or `value_out` are null. `kDifOk` otherwise.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_flash_ctrl_get_scratch(const dif_flash_ctrl_state_t *handle,
                                        uint32_t *value_out);

// TODO: PHY alerts, which are separate from the autogenerated alerts.

#ifdef __cplusplus
}  // extern "C"
#endif  // __cplusplus

#endif  // OPENTITAN_SW_DEVICE_LIB_DIF_DIF_FLASH_CTRL_H_
